<?php
/**
 * ImpSoft User Model
 * Any and all functionality related to the user model
 * 
 * @package ImpSoft
 * @subpackage ImpSoft Models
 * @copyright Luke Visinoni (luke.visinoni@gmail.com)
 * @author Luke Visinoni (luke.visinoni@gmail.com)
 * @license GNU Lesser General Public License
 */
class User extends ImpSoft_Db_Table {

    protected $_name = 'users';
    protected $_primary = 'user_id';
    protected $_dependentTables = array();
    protected $_rowClass = 'UserRow';
    protected $_required = array('username', 'password', 'password_verify', 'email', 'role');
    protected $_roles = array(
        'guest', // not logged in
        'member', // logged in, regular member
		'trusted', // logged in, trusted member
		'admin' // logged in, site administrator
    );
    
    public function getRoles() {
    
        return array_combine($this->_roles, $this->_roles);
    
    }
    /**
     * Hashes a value - used for passwords mostly
     */
    public static function hash($value, $salt = null, $pepper = null) {
    
		$prefix = '';
        if (!is_null($salt)) $prefix .= $salt . "$";
		if (!is_null($pepper)) $prefix .= $pepper . "$";
        return sha1($prefix . $value);
    
    }
    /**
     * Generates a password at random
     * 
     * @return string The users's new password (unhashed)
     */
    public static function generatePassword($length = null, $chars = null) {
    
        if (is_null($length)) $length = 8;
        if (is_null($chars)) {
            // if no chars are provided, use all upper and lowercase letters plus all numbers
            list($upper, $lower, $nums) = array(range('A', 'Z'), range('a', 'z'), range(0, 9));
            $chars = array_merge($upper, $lower, $nums);
        } else {
            // otherwise use the characters provided
            $chars = array_unique(str_split($chars));
        }
        
        $password = '';
        for($i = 0; $i < $length; $i++) {
            srand((double)microtime()*1000000);
            $random = rand(0,count($chars)-1);
            $password .= $chars[$random];
        }
        return $password;
    
    }
    
    public function getRules() {
    
        $rules = with(new Q_Rule_Set())
                ->add(new Q_Rule_Email(), 'email', 'Please provide an e-mail address for this user')
                ->add(new Q_Rule_Length(array('min' => 3, 'max' => 15)), 'username', 'Username must be between 3 and 15 characters in length')
				->add(new Q_Rule_Alnum(), 'username', 'Only numbers and digits are allowed in your username')
                ->add(new Q_Rule_Length(array('min' => 3, 'max' => 999999, 'optional' => true)), 'password', 'You need to provide at least 3 characters in your password')
                ->add(new Q_Rule_Match(array('match' => 'password_verify')), 'password', 'The passwords you entered do not match. Try again.')
                //->add(new Q_Rule_InArray(array('array' => $this->getRoles())), 'role', 'Sorry, that is not a valid role')
                ->add(new Q_Rule_NotNull(), array('password', 'password_verify'), 'This is a required field');
        return $rules;
    
    }
	/**
	 * Register a new user
	 *
	 * @param array $data 
	 * @return boolean
	 * @author Luke Visinoni
	 */
	public function registerUser($data, $pepper = null) {
	
		if (!is_array($data)) $data = array();
		$defaults = array(
			'username' => '',
			'password' => '',
			'email' => '',
			'user_role' => 'customer',
			'salt' => $this->generateSalt()
		);
		$data = array_merge($defaults, $data);
		$data['password'] = $this->hash($data['password'], $data['salt'], $pepper);
		$user = $this->createRow($data);
		$user->save();
		return $user;
	
	}
	/**
	 * Salt is 16 random ascii characters
	 */
	static public function generateSalt() {
	
		$chars = str_split("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-+=_?/.,<>:;{}[]|");
		$salt = '';
		$last = count($chars)-1;
		for ($i = 0;$i < 16; $i++) {
			$pos = rand(0, $last);
			$salt .= $chars[$pos];
		}
		return $salt;
	
	}
    
}